// -----------------------------------------------------------------
//     Learning Team C
//       Members:
//       Jon Mann
//       Jared Pack
//       Joshua Clayton
//     CS 4280  9:30 am
//     Team Assignment #3
//     Instructor: Mr. Rague
//     Due: 02/04/10
//     Version: 1.0
// -----------------------------------------------------------------
// This program clips lines 
// using the Cyrus - BeckClip clipper.
// -----------------------------------------------------------------


// -----------------------------------------------------------------
//   Change Control Section
// -----------------------------------------------------------------
//       Team Member:  Joshua Clayton
//       Version: 1.0
//       Date:  02/11/2010
//       Forked drawing program from group assignment 2
//
//       Team Member:  Joshua Clayton
//       Version: 1.1
//       Date:  02/11/2010
//       Fully implemented a ConvexPolygon class
//       Stubbed out clipping functions
//
//       Team Member:  Jon Mann
//       Version: 1.2
//       Date:  02/15/2010
//       set up test in draw_clipped_and_unclipped() function
//
//       Team Member:  Joshua Clayton
//       Version: 1.3
//       Date:  02/15/2010
//       wrote a function to draw random lines. added reshape, and animation
//
//       Team Member:  Joshua Clayton
//       Version: 1.4
//       Date:  02/15/2010
//       Added polygon drawing functionality
//       
//       Team Member:  Joshua Clayton
//       Version: 1.5
//       Date:  02/15/2010
//       Removed the hard coded polygon.
//       Added code to print instructions on the screen.
//
//       Team Member:  Jared Pack
//       Version: 1.4
//       Date:  02/15/2010
//       Narrative document
//
// -----------------------------------------------------------------

#ifdef _WIN32
#include<windows.h> // needed for windows systems
#endif

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include "canvas1.h"
#include "ClipPolygon.h"

#include<GL/gl.h>
#include<GL/glu.h>

static void init(void);
void myIdle(void);
void display(void);
void test(void);
void myMouse(int button, int state, int x, int y);
void myKeyboard(unsigned char key, int x, int y);
void draw_clipped_and_unclipped(Point2 *p1, Point2 *p2);
void randLines(void);
void myReshape(GLsizei w, GLsizei h);

//borrowed from http://www.lighthouse3d.com/opengl/glut/index.php?bmpfont
void renderBitmapString(float x, float y, float z, void *font, char *string);

static Canvas *viewCanvas;
static list<ClipPolygon>  clippers;
static ClipPolygon *mousePoly;

#define NUM_LINES 20
static Point2 p[2 * NUM_LINES];


void myIdle(void)
{
    static int seed = time(0);
    static clock_t base_clock = 0;
    static int counter = 0;

    srand(seed);

    //Check to see if half a second has passed
    clock_t current_clock = clock(); 
    if(current_clock - base_clock > (CLOCKS_PER_SEC >> 1))
    {
        counter = (counter + 1)%NUM_LINES;
        //the random values will step through the series
        RealRect win = viewCanvas->getWindow();
        int width = (int)(win.getR() - win.getL());
        int height = (int)(win.getT() - win.getB());

        p[counter].set((rand() % width) + win.getL(),
                       (rand() % height) + win.getB());
        p[NUM_LINES + counter].set((rand() % width) + win.getL(),
                                   (rand() % height)+ win.getB());

//        printf("p1:(%f, %f); p2 : (%f, %f)\n",
//               p[counter].getX(), p[counter].getY(),
//               p[NUM_LINES + counter].getX(), p[NUM_LINES + counter].getY());
        seed = rand();
        base_clock = current_clock;
    }

    glutPostRedisplay();
}

// entry point
int main (int argc, char **argv)
{
    int win_width = 640,
        win_height = 480,
        win_x = 50,
        win_y = 50;

    init();
    

    glutDisplayFunc(display);
    glutReshapeFunc(myReshape);
    glutMouseFunc(myMouse);
    glutKeyboardFunc(myKeyboard);
    glutIdleFunc(myIdle);

    glutMainLoop();

    return 0;
}

// builds our initial world window
void init(void)
{
    viewCanvas = new Canvas(640, 480, "Team C: Clipping demo");
    viewCanvas->setBackgroundColor(1.0, 1.0, 1.0);
    viewCanvas->setWindow(-320, 320, -240, 240);
//    glEnable(GL_POINT_SMOOTH | GL_LINE_SMOOTH);
}

void display(void)
{
    viewCanvas->clearScreen();
    glLineWidth(2);
    glColor3f(0.0, 1.0, 0.0);
    if (mousePoly)
    {
        mousePoly->draw_linestrip();
        mousePoly->getPoint(0).draw();
    }
    glLineWidth(1);
    glColor3f(0.0, 0.0, 0.0);
    for (list<ClipPolygon>::iterator i = clippers.begin(); i != clippers.end(); ++i)
    {
        i->draw();
    }

    randLines();
    glColor3f(0.0, 0.0, 0.0);
    renderBitmapString(-310.0, 220.0, 0.0, GLUT_BITMAP_HELVETICA_18, 
                       "Left click the mouse to draw a clipping polygon.");
    renderBitmapString(-310.0, 200.0, 0.0, GLUT_BITMAP_HELVETICA_18, 
                       "Press the 'C' key to close the polygon.");
    renderBitmapString(-310.0, 180.0, 0.0, GLUT_BITMAP_HELVETICA_18, 
                       "Press the 'X' key to delete the most recent polygon.");
    glutSwapBuffers();
}

void myKeyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
        case 'C':
        case 'c':
            clippers.push_back(*mousePoly);
            mousePoly = NULL;
            break;
//        case 'E':
//        case 'e':
//            if (mousePoly)
//            {
//                delete mousePoly;
//            }
//            mousePoly = clippers.back();
        case 'X':
        case 'x':
            if (!(clippers.empty()))
            {
                clippers.pop_back();
            }
        default:
            ; //do nothing
    }
}

void myMouse(int button, int state, int x, int y)
{
    static int numCorners = 0;
    if (button == GLUT_LEFT_BUTTON && (state == GLUT_DOWN))
    {
        IntRect vp = viewCanvas->getViewport();
        Point2 * pp = new Point2(x, vp.getT() - vp.getB() - y);
        viewCanvas->viewportToWindow(*pp);
        try
        {
            if (!mousePoly)
            {
                mousePoly = new ClipPolygon();
            }    
            mousePoly->appendPoint(*pp);
        }
        catch (char * str)
        {
            delete pp;
        }
    }
}

// generates random lines for testing against polygon
void randLines(void)
{
    Point2 clipped1, clipped2;
    bool draw_clipped = true;

    for (int i = 0; i < NUM_LINES; ++i)
    {
        glPointSize(6);
        glColor3f(0.0, 1.0, 0.0);
        p[i].draw();
        p[NUM_LINES + i].draw();

        glLineWidth(4);
        glColor3f(1.0, 0.0, 0.0);
        viewCanvas->moveTo(p[i]);
        viewCanvas->lineTo(p[NUM_LINES + i]);
        
        clipped1.set(p[i].getX(), p[i].getY());
        clipped2.set(p[NUM_LINES + i].getX(), p[NUM_LINES + i].getY());

        // clip against all polygons
        for (list<ClipPolygon>::iterator i = clippers.begin(); i != clippers.end(); ++i)
        {
            if (!(draw_clipped = i->CyrusBeckClip(clipped1, clipped2)))
            {
                break;
            }
        }
        if (draw_clipped)
        {
            glColor3f(0.0, 0.0, 1.0);
            viewCanvas->moveTo(clipped1);
            viewCanvas->lineTo(clipped2);
        }
    }
    
}

void myReshape(GLsizei w, GLsizei h)
{
    float left, right, bot, top;
    if (w > (h * 1.33333333333))
    {
        left = -240.0 * w / h;
        right = 240.0 * w / h;
        bot = -240.0;
        top = 240;
    }
    else
    {
        left = -320.0;
        right = 320.0;
        bot = -320 * h / w;
        top = 320.0 * h / w;
    }
    viewCanvas->setWindow(left, right, bot, top);
    viewCanvas->setViewport(0, w, 0, h);
}

void renderBitmapString(float x, float y, float z, void *font, char *string)
{  
    char *c;
    glRasterPos3f(x, y,z);
    for (c=string; *c != '\0'; c++)
    {
         glutBitmapCharacter(font, *c);
    }
}

